﻿using Avalon.Core.Data;
using Avalon.Core.Data.Templates;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Security;

namespace Avalon.Core.Providers
{
    public class MembershipProvider : System.Web.Security.MembershipProvider
    {
        private IRepository<AvalonUser> userRepository = RepositoryConfig.Initialize<AvalonUser>();
        public override string ApplicationName { get; set; }

        public bool ChangePassword(string username, string newPassword)
        {
            var user = userRepository.Get().First(u => u.UserName == username);
            user.Password = EncriptionProvider.EncryptPassword(newPassword);
            return userRepository.SaveChanges() == 1;
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            byte[] pw = EncriptionProvider.EncryptPassword(oldPassword);

            var user = userRepository.Get().First(u => u.UserName == username && u.Password == pw);
            user.Password = EncriptionProvider.EncryptPassword(newPassword);
            return userRepository.SaveChanges() == 1;
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override System.Web.Security.MembershipUser CreateUser(
            string username,
            string password,
            string email,
            string passwordQuestion,
            string passwordAnswer,
            bool isApproved,
            object providerUserKey,
            out System.Web.Security.MembershipCreateStatus status)
        {
            return CreateUser(username, password, string.Empty, string.Empty, email, out status);
        }

        public MembershipUser CreateUser(
            string username,
            string password,
            string firstname,
            string lastname,
            string email,
            out MembershipCreateStatus status)
        {
            //Cannot insert a duplicate user
            if (userRepository.Get().FirstOrDefault(u => u.UserName == username) != null)
            {
                status = MembershipCreateStatus.DuplicateUserName;
                return null;
            }

            AvalonUser user = new AvalonUser();
            user.UserName = username;
            user.Password = EncriptionProvider.EncryptPassword(password);
            user.FirstName = firstname;
            user.LastName = lastname;
            user.Email = email;
            user.IsApproved = true;
            user.DateRegistered = DateTime.Now;

            userRepository.Add(user);

            try
            {
                userRepository.SaveChanges();
                status = MembershipCreateStatus.Success;
            }
            catch
            {
                status = MembershipCreateStatus.UserRejected;
            }

            return GetUser(username, false);
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            try
            {
                Guid userId = userRepository.Get().First(u => u.UserName == username).Id;
                userRepository.Delete(userId);
                return true;
            }
            catch
            {
                throw new Exception("Failed to delete the user from the database.");
            }
        }

        public override bool EnablePasswordReset
        {
            get { return false; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return false; }
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            //Get the total users
            totalRecords = userRepository.Get().Count();
            
            //Create a new MambershipUserCollection from all paged users in the database.
            var users = new MembershipUserCollection();
            userRepository
                .Get()
                .OrderBy(u => u.UserName)
                .Skip(pageIndex * pageSize)
                .Take(pageSize)
                .Select(user => createMembershipUser(user))
                .ToList()
                .ForEach(membershipUser => userRepository.Add(membershipUser));

            //return the users.
            return users;
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            AvalonUser user = userRepository.Get().FirstOrDefault(u => u.UserName == username);
            if (user != null) return createMembershipUser(user);
            else return null;
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            AvalonUser user = userRepository.Get().FirstOrDefault(u => u.Id == (Guid)providerUserKey);
            if (user != null) return createMembershipUser(user);
            else return null;
        }

        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); }
        }

        public override int MinRequiredPasswordLength
        {
            get { return 8; }
        }

        public override int PasswordAttemptWindow
        {
            get { return 3; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return false; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return true; }
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        public override bool ValidateUser(string username, string password)
        {
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) return false;
            byte[] _pw = EncriptionProvider.EncryptPassword(password);
            return userRepository.Get().FirstOrDefault(u => u.UserName == username && u.Password == _pw) != null;
        }

        protected override byte[] EncryptPassword(byte[] password)
        {
            return EncriptionProvider.EncryptPassword(password);
        }

        protected override byte[] DecryptPassword(byte[] encodedPassword)
        {
            throw new Exception("Decrypting passwords is not allowed.");
        }

        private MembershipUser createMembershipUser(AvalonUser user)
        {
            return new MembershipUser(
                this.Name,
                user.UserName,
                user.Id,
                user.Email,
                string.Empty,
                string.Empty,
                user.IsApproved,
                user.IsApproved,
                user.DateRegistered,
                DateTime.MinValue,
                DateTime.MinValue,
                DateTime.MinValue,
                DateTime.MinValue);
        }
    }
}
